﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.Composition;
using System.Windows.Input;
using ScrumFactory.Composition;
using ScrumFactory.Composition.ViewModel;
using ScrumFactory.Services;
using ScrumFactory.Windows.Helpers.Extensions;

namespace ScrumFactory.Tasks.ViewModel {

    [Export]
    [Export(typeof(IStartsWithApp))]
    public class UserTasksSelectorViewModel : BasePanelViewModel, IDialogViewModel, IStartsWithApp, INotifyPropertyChanged {

        private IEventAggregator aggregator;
        private IBackgroundExecutor executor;
        private ITasksService tasksService;
        private IAuthorizationService authorizator;
        private IDialogService dialogs;

        private ICollection<TaskViewModel> tasks;

        public string TrackingTaskUId { get; private set; }

        private System.DateTime lastLoadTime;

        [Import]
        private FinishTaskDialogViewModel FinishDialog { get; set; }
        
        [ImportingConstructor]
        public UserTasksSelectorViewModel(
            [Import]IBackgroundExecutor executor,
            [Import]IEventAggregator aggregator,
            [Import]ITasksService tasksService,
            [Import] IDialogService dialogs,
            [Import]IAuthorizationService authorizator) {

                this.executor = executor;
                this.aggregator = aggregator;
                this.tasksService = tasksService;
                this.dialogs = dialogs;
                
                this.authorizator = authorizator;

                aggregator.Subscribe(ScrumFactoryEvent.ShowUserTasksSelector, ShowTaskSelector);
        
                ShowTaskDetailCommand = new DelegateCommand<TaskViewModel>(ShowTaskDetail);
        }

        [Import]
        private TaskViewModel detailViewModel;

        private bool isTracking;
        private DateTime? startTrackingTime = null;


        private void ShowTaskDetail(TaskViewModel task) {
            ((UserTasksSelector)View).Hide();
            detailViewModel.ShowDetail(task.Task);                                                    
        }

        public void StopTaskTrack() {
            StopTaskTrack(true);
        }

        private void StopTaskTrack(bool publish) {
            decimal hours = (decimal) TrackEllipsedTime.TotalHours;
            string id = TrackingTaskUId;
            startTrackingTime = null;
            TrackingTaskUId = null;
            executor.StartBackgroundTask(
                () => {
                    tasksService.ChangeTaskEffectiveHours(id, hours, true);
                },
                () => {});
            if(publish)
                aggregator.Publish<string>(ScrumFactoryEvent.TaskTrackChanged, TrackingTaskUId);    
        }


        public void StartTrack(Task task) {
            
            if (TrackingTaskUId != null)
                StopTaskTrack(false);

            TrackingTaskUId = task.TaskUId;
            startTrackingTime = DateTime.Now;
            aggregator.Publish<string>(ScrumFactoryEvent.TaskTrackChanged, TrackingTaskUId);    
        }

        /// <summary>
        /// Gets the ellipsed hours since the current tracking task was started.
        /// </summary>
        /// <value>The ellipsed hours.</value>
        public TimeSpan TrackEllipsedTime {
            get {
                if (!startTrackingTime.HasValue)
                    return new TimeSpan();
                return DateTime.Now.Subtract(startTrackingTime.Value);
            }
        }

        /// <summary>
        /// Shows the task selector.
        /// </summary>
        private void ShowTaskSelector() {
            if (authorizator.SignedMemberProfile == null)
                return;            
            // just to save server requests, load only after each 5 seconds
            if(DateTime.Now.Subtract(lastLoadTime).TotalSeconds > 5)
                LoadTasks();
            
            Show();
        }

        public ICollection<TaskViewModel> Tasks {
            get {
                return tasks;
            }
            set {
                tasks = value;
                OnPropertyChanged("Tasks");
            }
        }

        /// <summary>
        /// Loads the tasks.
        /// </summary>
        private void LoadTasks() {
            IsLoadingData = true;
  
            executor.StartBackgroundTask<ICollection<Task>>(
                () => { return tasksService.GetUserTasks(authorizator.SignedMemberProfile.MemberUId); },
                tasks => {
                    List<TaskViewModel> tempList = new List<TaskViewModel>();
                    foreach (Task t in tasks) {
                        TaskViewModel vm = new TaskViewModel(executor, tasksService, aggregator, dialogs, authorizator, t, this);
                        vm.FinishDialog = this.FinishDialog;
                        tempList.Add(vm);                        
                    }
                    ClearTasks();
                    Tasks = new ObservableCollection<TaskViewModel>(tempList.OrderByDescending(t => t.IsTracking).ThenByDescending(t => t.Task.Priority).ThenByDescending(t => t.Task.TaskType));
                    IsLoadingData = false;
                    lastLoadTime = DateTime.Now;
                });
        }

        /// <summary>
        /// Make sure to call dispose in every task to unbind commands.
        /// </summary>
        private void ClearTasks() {
            ShowTaskDetailCommand = null;
            Tasks.ClearAndDispose();
            Tasks = new List<TaskViewModel>();

            // need to this to release the taskview model from memory
            // 'cuz the TaskViewModel are binded to this command passing themselves as parameters
            // it create a reference and GC never collect the viewmodels..
            ShowTaskDetailCommand = new DelegateCommand<TaskViewModel>(ShowTaskDetail);
            
        }

        
        public ICommand ShowTaskDetailCommand { get; set; }
        

        #region IDialogViewModel Members
        
        [Import(typeof(UserTasksSelector))]
        public Composition.View.IDialogView View { get; set; }

        public void Show() {
            View.Show();
        }

        public void Close() {
            View.Close();
        }

        public System.Windows.Input.ICommand CloseWindowCommand { get; set; }


        public System.Windows.Input.ICommand MoveWindowCommand {
            get { throw new NotSupportedException(); }
        }
        
        public System.Windows.Input.ICommand MinimizeWindowCommand {
            get { throw new NotSupportedException(); }
        }

        public System.Windows.Input.ICommand MaximizeWindowCommand {
            get { throw new NotSupportedException(); }
        }

        #endregion
    }
}
